import 'package:flutter/material.dart';

import '../../../utils/ex/string_ex.dart';
import '../ex/extension.dart';
import 'base/axis.dart';
import 'base/base_axis_chart.dart';

/// X轴绘制器
///
/// Created by wanggaowan on 2023/9/15 10:52
class XAxisRender<C extends BaseAxisChartDelegate>
    with BaseXAxisRenderMixin<C> {
  XAxisRender({this.isDrawLabelByGridLine = true});

  /// 标签是否与网格线水平居中对齐，如果为false，则标签与网格中心点水平居中对齐
  final bool isDrawLabelByGridLine;

  @override
  void onDraw(C chart, Canvas canvas, Rect rect, double gridWidth,
      double labelMaxHeight, double yAxisRange) {
    var textPaint = TextPainter(textDirection: TextDirection.ltr);
    var paint = Paint();
    var path = Path();

    // 绘制轴线
    var xAxis = chart.xAxis;
    var yAxis = chart.yAxis;
    if(xAxis.lineWidth > 0) {
      paint.color = xAxis.lineColor;
      paint.strokeWidth = xAxis.lineWidth;
      paint.style = PaintingStyle.stroke;
      var y = rect.top + (rect.bottom - rect.top) / 2;
      path.moveTo(rect.left, y);
      path.lineTo(rect.right, y);
      if (xAxis.lineDash != null) {
        path = path.dashPath(xAxis.lineDash!);
      }
      canvas.drawPath(path, paint);
    }
    xAxis.$drawRect = rect;

    var labelList = xAxis.labelList;
    if (labelList == null || labelList.isEmpty) {
      return;
    }

    // 绘制轴线文本
    var xLineDrawStart = rect.left + xAxis.startPadding;
    paint.color = xAxis.gridLineColor;
    paint.strokeWidth = xAxis.gridLineWidth;
    paint.style = PaintingStyle.stroke;
    for (int i = 0; i < labelList.length; i++) {
      if (gridWidth > 0 && labelMaxHeight > 0) {
        if (isDrawLabelByGridLine) {
          drawLabelByGridLine(
              canvas,
              textPaint,
              i,
              labelList,
              xAxis,
              gridWidth,
              rect.bottom,
              rect.right,
              labelMaxHeight,
              xLineDrawStart + yAxis.lineWidth / 2);
        } else {
          drawLabelByGridCenter(
              canvas,
              textPaint,
              i,
              labelList,
              xAxis,
              gridWidth,
              rect.bottom,
              labelMaxHeight,
              xLineDrawStart + yAxis.lineWidth / 2);
        }
      }

      if (i > 0 && xAxis.gridLineWidth > 0) {
        // 绘制X轴网格线，如果xAxis.gridUseEndPadding为true，则X轴结束点实际都在Y轴最后一根轴线下面
        path.reset();
        path.moveTo(
            xLineDrawStart + yAxis.lineWidth,
            xAxis.gridUseEndPadding
                ? rect.top - yAxisRange + yAxis.endPadding
                : rect.top - yAxisRange);
        path.lineTo(
            xLineDrawStart + yAxis.lineWidth,
            xAxis.gridUseStartPadding
                ? rect.top - yAxis.startPadding
                : rect.top);
        if (xAxis.gridLineDash != null) {
          path = path.dashPath(xAxis.gridLineDash!);
        }
        canvas.drawPath(path, paint);
      }

      xLineDrawStart += gridWidth;
    }

    if (!isDrawLabelByGridLine && xAxis.gridLineWidth > 0) {
      // isDrawLabelByGridLine为false，此时标签与网格中心对齐，网格线要多画一条

      // 绘制X轴网格线，如果xAxis.gridUseEndPadding为true，则X轴结束点实际都在Y轴最后一根轴线下面
      path.reset();
      path.moveTo(
          xLineDrawStart + yAxis.lineWidth,
          xAxis.gridUseEndPadding
              ? rect.top - yAxisRange + yAxis.endPadding
              : rect.top - yAxisRange);
      path.lineTo(xLineDrawStart + yAxis.lineWidth,
          xAxis.gridUseStartPadding ? rect.top - yAxis.startPadding : rect.top);
      if (xAxis.gridLineDash != null) {
        path = path.dashPath(xAxis.gridLineDash!);
      }
      canvas.drawPath(path, paint);
    }

    textPaint.dispose();
  }

  /// 绘制标签，内容与网格中点水平居中对齐
  @protected
  void drawLabelByGridCenter(
      Canvas canvas,
      TextPainter textPaint,
      int index,
      List<Label> labels,
      BaseXAxis xAxis,
      double gridWidth,
      double bottom,
      double labelMaxHeight,
      double xLineDrawStart) {
    // 绘制x轴文本
    var label = labels[index];
    var text = label.value;
    var labelOffset = xAxis.labelOffsetAxis;

    if (text.isNullOrEmpty || label.weight <= 0) {
      return;
    }

    var maxWidth = gridWidth * label.weight - xAxis.labelHorizontalPadding;
    if (maxWidth <= 0) {
      // 文本绘制空间没有
      return;
    }

    var labelAlign = xAxis.labelAlign;
    var overAlign = xAxis.labelOverAlign;

    textPaint.text = TextSpan(
      text: text,
      style: TextStyle(
          fontSize: xAxis.labelTextSize,
          color: xAxis.labelColor,
          overflow: xAxis.textOverflow),
    );
    textPaint.maxLines = xAxis.labelMaxLines;
    textPaint.textAlign = xAxis.labelAlign;
    textPaint.ellipsis =
        xAxis.textOverflow == TextOverflow.ellipsis ? kEllipsis : null;

    textPaint.layout(minWidth: maxWidth, maxWidth: maxWidth);
    if (xAxis.labelMaxLines > 1 &&
        overAlign != labelAlign &&
        textPaint.computeLineMetrics().length > 1) {
      textPaint.textAlign = overAlign;
      textPaint.layout(minWidth: maxWidth, maxWidth: maxWidth);
    }

    var overWidthHalf = (maxWidth - gridWidth) / 2;
    var tempRectF = Rect.fromLTRB(
        xLineDrawStart - overWidthHalf,
        bottom,
        xLineDrawStart + gridWidth + overWidthHalf,
        bottom + labelOffset + labelMaxHeight);

    if (xAxis.textOverflow != TextOverflow.visible) {
      canvas.save();
      canvas.clipRect(tempRectF);
    }

    textPaint.paint(canvas, Offset(tempRectF.left, bottom + labelOffset));

    if (xAxis.textOverflow != TextOverflow.visible) {
      canvas.restore();
    }
  }

  /// 绘制标签，内容与网格线水平居中对齐
  @protected
  void drawLabelByGridLine(
      Canvas canvas,
      TextPainter textPaint,
      int index,
      List<Label> labels,
      BaseXAxis xAxis,
      double gridWidth,
      double bottom,
      double end,
      double labelMaxHeight,
      double xLineDrawStart) {
    // 绘制x轴文本
    var label = labels[index];
    var text = label.value;
    var labelOffset = xAxis.labelOffsetAxis;

    if (text.isNullOrEmpty || label.weight <= 0) {
      return;
    }

    var maxWidth = gridWidth * label.weight - xAxis.labelHorizontalPadding;
    if (maxWidth <= 0) {
      // 文本绘制空间没有
      return;
    }

    var labelAlign = xAxis.labelAlign;
    var overAlign = xAxis.labelOverAlign;

    textPaint.text = TextSpan(
      text: text,
      style: TextStyle(
          fontSize: xAxis.labelTextSize,
          color: xAxis.labelColor,
          overflow: xAxis.textOverflow),
    );
    textPaint.maxLines = xAxis.labelMaxLines;
    textPaint.ellipsis =
        xAxis.textOverflow == TextOverflow.ellipsis ? kEllipsis : null;

    Rect tempRect;
    if (index == 0) {
      tempRect = parseStartIndexRect(xAxis, textPaint, maxWidth, xLineDrawStart,
          bottom, end, labelMaxHeight);
    } else if (index == labels.length - 1) {
      tempRect = parseEndIndexRect(
          xAxis, textPaint, maxWidth, bottom, end, labelMaxHeight);
    } else {
      var widthHalf = maxWidth / 2;
      textPaint.textAlign = xAxis.labelAlign;
      if (xAxis.labelMaxLines > 1 && overAlign != labelAlign) {
        textPaint.layout(minWidth: maxWidth, maxWidth: maxWidth);
        if (textPaint.computeLineMetrics().length > 1) {
          textPaint.textAlign = overAlign;
        }
      }

      tempRect = Rect.fromLTRB(xLineDrawStart - widthHalf, bottom,
          xLineDrawStart + widthHalf, bottom + labelOffset + labelMaxHeight);
    }

    if (xAxis.textOverflow != TextOverflow.visible) {
      canvas.save();
      canvas.clipRect(tempRect);
    }

    double width = tempRect.width;
    textPaint.layout(minWidth: width, maxWidth: width);
    textPaint.paint(canvas, Offset(tempRect.left, bottom + labelOffset));

    if (xAxis.textOverflow != TextOverflow.visible) {
      canvas.restore();
    }
  }

  /// 解析起始坐标文本绘制的范围
  @protected
  Rect parseStartIndexRect(
    BaseXAxis xAxis,
    TextPainter textPaint,
    double maxWidth,
    double xLineDrawStart,
    double bottom,
    double end,
    double labelMaxHeight,
  ) {
    // x轴绘制起始偏移距离
    double leftOffset = 0;
    var widthHalf = maxWidth / 2;
    var leftWidth = xLineDrawStart;

    var labelAlign = xAxis.labelAlign;
    var overAlign = xAxis.labelOverAlign;
    var labelOffset = xAxis.labelOffsetAxis;

    Rect tempRect;
    // 起始点标签绘制宽度是否与中间标签宽度一致
    double maxTextWidth;
    if (leftWidth < widthHalf) {
      maxTextWidth = widthHalf + leftWidth;
      if (labelAlign == TextAlign.center) {
        // 与轴线中心对齐
        if (xLineDrawStart - widthHalf < leftOffset) {
          // 标签中心与View Padding距离不够期望宽度的一半
          widthHalf = xLineDrawStart - leftOffset;
        }

        textPaint.layout(minWidth: widthHalf * 2, maxWidth: widthHalf * 2);
        if (textPaint.computeLineMetrics().length > 1) {
          if (xAxis.labelMaxLines > 1) {
            textPaint.layout(minWidth: maxTextWidth, maxWidth: maxTextWidth);
            if (textPaint.computeLineMetrics().length > 1) {
              // 居中时可用宽度和非居中可用宽度时都超出一行，此时对齐方式使用用户设置的
              textPaint.textAlign = overAlign;
              if (overAlign == TextAlign.center) {
                tempRect = Rect.fromLTRB(
                    xLineDrawStart - widthHalf,
                    bottom,
                    xLineDrawStart + widthHalf,
                    bottom + labelOffset + labelMaxHeight);
              } else {
                tempRect = Rect.fromLTRB(
                    leftOffset,
                    bottom,
                    xLineDrawStart + maxWidth / 2,
                    bottom + labelOffset + labelMaxHeight);
              }
            } else {
              // 居中时可用宽度超出一行但是非居中可用宽度没都超出一行，
              // 此时对齐方式使用靠左对齐，因为此标签为起始标签
              textPaint.textAlign = TextAlign.left;
              tempRect = Rect.fromLTRB(
                  leftOffset,
                  bottom,
                  xLineDrawStart + maxWidth / 2,
                  bottom + labelOffset + labelMaxHeight);
            }
          } else {
            textPaint.textAlign = TextAlign.left;
            tempRect = Rect.fromLTRB(
                leftOffset,
                bottom,
                xLineDrawStart + maxWidth / 2,
                bottom + labelOffset + labelMaxHeight);
          }
        } else {
          textPaint.textAlign = labelAlign;
          tempRect = Rect.fromLTRB(
              xLineDrawStart - widthHalf,
              bottom,
              xLineDrawStart + widthHalf,
              bottom + labelOffset + labelMaxHeight);
        }
      } else if (overAlign == TextAlign.center && xAxis.labelMaxLines > 1) {
        textPaint.layout(minWidth: maxTextWidth, maxWidth: maxTextWidth);
        if (textPaint.computeLineMetrics().length > 1) {
          // 居中时可用宽度和非居中可用宽度时都超出一行，此时对齐方式使用用户设置的
          textPaint.textAlign = overAlign;
          if (xLineDrawStart - widthHalf < leftOffset) {
            // 标签中心与View Padding距离不够期望宽度的一半
            widthHalf = xLineDrawStart - leftOffset;
          }
          tempRect = Rect.fromLTRB(
              xLineDrawStart - widthHalf,
              bottom,
              xLineDrawStart + widthHalf,
              bottom + labelOffset + labelMaxHeight);
        } else {
          // 居中时可用宽度超出一行但是非居中可用宽度没都超出一行，
          // 此时对齐方式使用靠左对齐，因为此标签为起始标签
          textPaint.textAlign = labelAlign;
          tempRect = Rect.fromLTRB(
              leftOffset,
              bottom,
              xLineDrawStart + maxWidth / 2,
              bottom + labelOffset + labelMaxHeight);
        }
      } else {
        textPaint.textAlign = xAxis.labelAlign;
        if (xAxis.labelMaxLines > 1 && overAlign != labelAlign) {
          textPaint.layout(minWidth: maxTextWidth, maxWidth: maxTextWidth);
          if (textPaint.computeLineMetrics().length > 1) {
            textPaint.textAlign = overAlign;
          }
        }

        tempRect = Rect.fromLTRB(
            leftOffset,
            bottom,
            xLineDrawStart + maxWidth / 2,
            bottom + labelOffset + labelMaxHeight);
      }
    } else {
      maxTextWidth = maxWidth;
      textPaint.textAlign = xAxis.labelAlign;
      if (xAxis.labelMaxLines > 1 && overAlign != labelAlign) {
        textPaint.layout(minWidth: maxTextWidth, maxWidth: maxTextWidth);
        if (textPaint.computeLineMetrics().length > 1) {
          textPaint.textAlign = overAlign;
        }
      }
      tempRect = Rect.fromLTRB(xLineDrawStart - widthHalf, bottom,
          xLineDrawStart + widthHalf, bottom + labelOffset + labelMaxHeight);
    }
    return tempRect;
  }

  /// 解析结束坐标文本绘制的范围
  @protected
  Rect parseEndIndexRect(
    BaseXAxis xAxis,
    TextPainter textPaint,
    double maxWidth,
    double bottom,
    double end,
    double labelMaxHeight,
  ) {
    // x轴绘制起始偏移距离
    var centerX = end - xAxis.endPadding;
    var widthHalf = maxWidth / 2;
    var rightWidth = xAxis.endPadding;

    var labelAlign = xAxis.labelAlign;
    var overAlign = xAxis.labelOverAlign;
    var labelOffset = xAxis.labelOffsetAxis;

    Rect tempRect;
    // 起始点标签绘制宽度是否与中间标签宽度一致
    double maxTextWidth;
    if (rightWidth < widthHalf) {
      maxTextWidth = widthHalf + widthHalf;
      if (labelAlign == TextAlign.center) {
        // 与轴线中心对齐
        if (centerX + widthHalf > end) {
          // 标签中心与View Padding距离不够期望宽度的一半
          widthHalf = end - centerX;
        }

        textPaint.layout(minWidth: widthHalf * 2, maxWidth: widthHalf * 2);
        if (textPaint.computeLineMetrics().length > 1) {
          if (xAxis.labelMaxLines > 1) {
            textPaint.layout(minWidth: maxTextWidth, maxWidth: maxTextWidth);
            if (textPaint.computeLineMetrics().length > 1) {
              // 居中时可用宽度和非居中可用宽度时都超出一行，此时对齐方式使用用户设置的
              textPaint.textAlign = overAlign;
              if (overAlign == TextAlign.center) {
                tempRect = Rect.fromLTRB(centerX - widthHalf, bottom,
                    centerX + widthHalf, bottom + labelOffset + labelMaxHeight);
              } else {
                tempRect = Rect.fromLTRB(centerX - maxWidth / 2, bottom, end,
                    bottom + labelOffset + labelMaxHeight);
              }
            } else {
              // 居中时可用宽度超出一行但是非居中可用宽度没都超出一行，
              // 此时对齐方式使用靠左对齐，因为此标签为起始标签
              textPaint.textAlign = TextAlign.left;
              tempRect = Rect.fromLTRB(centerX - maxWidth / 2, bottom, end,
                  bottom + labelOffset + labelMaxHeight);
            }
          } else {
            textPaint.textAlign = TextAlign.left;
            tempRect = Rect.fromLTRB(centerX - maxWidth / 2, bottom, end,
                bottom + labelOffset + labelMaxHeight);
          }
        } else {
          textPaint.textAlign = labelAlign;
          tempRect = Rect.fromLTRB(centerX - widthHalf, bottom,
              centerX + widthHalf, bottom + labelOffset + labelMaxHeight);
        }
      } else if (overAlign == TextAlign.center && xAxis.labelMaxLines > 1) {
        textPaint.layout(minWidth: maxTextWidth, maxWidth: maxTextWidth);
        if (textPaint.computeLineMetrics().length > 1) {
          // 居中时可用宽度和非居中可用宽度时都超出一行，此时对齐方式使用用户设置的
          textPaint.textAlign = overAlign;
          if (centerX + widthHalf > end) {
            // 标签中心与View Padding距离不够期望宽度的一半
            widthHalf = end - centerX;
          }
          tempRect = Rect.fromLTRB(centerX - widthHalf, bottom,
              centerX + widthHalf, bottom + labelOffset + labelMaxHeight);
        } else {
          // 居中时可用宽度超出一行但是非居中可用宽度没都超出一行，
          // 此时对齐方式使用靠左对齐，因为此标签为起始标签
          textPaint.textAlign = labelAlign;
          tempRect = Rect.fromLTRB(centerX - widthHalf, bottom, end,
              bottom + labelOffset + labelMaxHeight);
        }
      } else {
        textPaint.textAlign = xAxis.labelAlign;
        if (xAxis.labelMaxLines > 1 && overAlign != labelAlign) {
          textPaint.layout(minWidth: maxTextWidth, maxWidth: maxTextWidth);
          if (textPaint.computeLineMetrics().length > 1) {
            textPaint.textAlign = overAlign;
          }
        }

        tempRect = Rect.fromLTRB(centerX - widthHalf, bottom, end,
            bottom + labelOffset + labelMaxHeight);
      }
    } else {
      maxTextWidth = maxWidth;
      textPaint.textAlign = xAxis.labelAlign;
      if (xAxis.labelMaxLines > 1 && overAlign != labelAlign) {
        textPaint.layout(minWidth: maxTextWidth, maxWidth: maxTextWidth);
        if (textPaint.computeLineMetrics().length > 1) {
          textPaint.textAlign = overAlign;
        }
      }
      tempRect = Rect.fromLTRB(centerX - widthHalf, bottom, centerX + widthHalf,
          bottom + labelOffset + labelMaxHeight);
    }
    return tempRect;
  }
}



